package com.gitee.wsl.compose.ui.base

import androidx.compose.foundation.clickable
import androidx.compose.foundation.gestures.Orientation
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.ColumnScope
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.WindowInsets
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.heightIn
import androidx.compose.foundation.layout.navigationBars
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.union
import androidx.compose.foundation.layout.windowInsetsPadding
import androidx.compose.material3.Divider
import androidx.compose.material3.LocalContentColor
import androidx.compose.material3.LocalTextStyle
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.ProvideTextStyle
import androidx.compose.material3.Surface
import androidx.compose.runtime.Composable
import androidx.compose.runtime.CompositionLocalProvider
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.semantics.Role
import androidx.compose.ui.text.TextStyle
import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.text.style.TextAlign
import androidx.compose.ui.unit.Dp
import androidx.compose.ui.unit.dp
import androidx.compose.ui.util.fastForEach
import androidx.compose.ui.util.fastForEachIndexed
import com.gitee.wsl.compose.ui.section.CupertinoSectionTokens
import androidx.compose.material3.HorizontalDivider

/**
 * Style of the Cupertino alert action buttons
 * */
enum class AlertActionStyle {

    /**
     * Default action button
     * */
    Default {
        override fun apply(style: TextStyle, dark: Boolean): TextStyle {
            return style.copy(
                fontWeight = FontWeight.Normal,
                color = Color.Blue,
                textAlign = TextAlign.Center
            )
        }
    },

    /**
     * Cancel action button. It will be displayed below the other buttons
     * with different container color and bolder font
     * */
    Cancel {
        override fun apply(style: TextStyle, dark: Boolean): TextStyle {
            return style.copy(
                fontWeight = FontWeight.Bold,
                color = Color.Blue,
                textAlign = TextAlign.Center
            )
        }
    },

    /**
     * Destructive action button. It will be red
     * */
    Destructive {
        override fun apply(style: TextStyle, dark: Boolean): TextStyle {
            return style.copy(
                fontWeight = FontWeight.Normal,
                color = Color.Blue,
                textAlign = TextAlign.Center
            )
        }
    };


    internal abstract fun apply(style: TextStyle, dark: Boolean): TextStyle
}


interface AlertActionsScope {

    fun action(
        onClick : () -> Unit,
        style : AlertActionStyle = AlertActionStyle.Default,
        enabled : Boolean = true,
        title : @Composable () -> Unit
    )
}

/**
 * Alert controller button with default style
 * */
fun AlertActionsScope.default(
    onClick : () -> Unit,
    enabled : Boolean = true,
    title : @Composable () -> Unit
) = action(
    onClick = onClick,
    style = AlertActionStyle.Default,
    enabled = enabled,
    title = title
)

/**
 * Alert controller button with destructive style
 * */
fun AlertActionsScope.destructive(
    onClick : () -> Unit,
    enabled : Boolean = true,
    title : @Composable () -> Unit
) = action(
    onClick = onClick,
    style = AlertActionStyle.Destructive,
    enabled = enabled,
    title = title
)

/**
 * Alert controller button with cancel style
 * */
fun AlertActionsScope.cancel(
    onClick : () -> Unit,
    enabled : Boolean = true,
    title : @Composable () -> Unit
) = action(
    onClick = onClick,
    style = AlertActionStyle.Cancel,
    enabled = enabled,
    title = title
)


class AlertButtonsScopeImpl(
    private val orientation: Orientation,
) : AlertActionsScope {

    private val buttons = mutableListOf<@Composable () -> Unit>()

    override fun action(
        onClick: () -> Unit,
        style: AlertActionStyle,
        enabled: Boolean,
        title: @Composable () -> Unit
    ) {
        buttons.add {
            Box(
                Modifier
                    .clickable(
                        enabled = enabled,
                        onClick = onClick,
                        role = Role.Button,
                    )
                    .fillMaxSize(),
                contentAlignment = Alignment.Center,
                content = {
                    val s = style.apply(MaterialTheme.typography.bodyMedium, false)
                    ProvideTextStyle(
                        s.copy(
                            color = if (enabled) s.color
                            else MaterialTheme.colorScheme.tertiary
                        )
                    ) {
                        CompositionLocalProvider(
                            LocalContentColor provides LocalTextStyle.current.color
                        ) {
                            title()
                        }
                    }
                }
            )
        }
    }

    @Composable
    fun Content() {
         Column {
                HorizontalDivider()
                if (orientation == Orientation.Horizontal) {
                    Row(
                        modifier = Modifier
                            .height(CupertinoSectionTokens.MinHeight)
                    ) {
                        buttons.fastForEachIndexed { i, btn ->
                            Box(Modifier.weight(1f)) {
                                btn()
                            }
                            if (i != buttons.lastIndex) {
                                Divider()
                            }
                        }
                    }
                } else {
                    buttons.fastForEachIndexed { i, btn ->
                        Box(
                            modifier = Modifier
                                .fillMaxWidth()
                                .height(CupertinoSectionTokens.MinHeight)
                        ) {
                            btn()
                        }
                        if (i != buttons.lastIndex) {
                            HorizontalDivider()
                        }
                    }
                }
            }
    }
}

class ActionSheetImpl(
    private val hasTitle : Boolean,
    private val primaryContainerColor : Color,
    private val secondaryContainerColor: Color,
) : AlertActionsScope {

    private val buttons = mutableListOf<Pair<AlertActionStyle, @Composable () -> Unit>>()

    override fun action(
        onClick: () -> Unit,
        style: AlertActionStyle,
        enabled: Boolean,
        title: @Composable () -> Unit
    ) {
        buttons.add(style to {
            Box(
                modifier = Modifier
                    .clickable(
                        enabled = enabled,
                        onClick = onClick,
                        role = Role.Button,
                    )
                    .fillMaxWidth()
                    .heightIn(min = ActionSheetButtonHeight),
                contentAlignment = Alignment.Center,
                content = {
                    val s =  style.apply(MaterialTheme.typography.titleMedium, false)
                    ProvideTextStyle(
                        s.copy(
                            fontWeight = if (style == AlertActionStyle.Cancel)
                                FontWeight.SemiBold else FontWeight.Normal,
                            color = if (enabled)
                                s.color
                            else MaterialTheme.colorScheme.tertiary
                        )
                    ) {
                        CompositionLocalProvider(
                            LocalContentColor provides LocalTextStyle.current.color
                        ) {
                            title()
                        }
                    }
                }
            )
        })
    }

    @Composable
    fun Content(title: (@Composable ColumnScope.() -> Unit)? = null) {
            Column(
                modifier = Modifier
                    .windowInsetsPadding(ActionSheetWindowInsets),
            ) {
                Surface(
                    modifier = Modifier
                        .padding(
                            start = ActionSheetSidePadding,
                            end = ActionSheetSidePadding,
                            top = ActionSheetSidePadding,
                        ),
                    shape = MaterialTheme.shapes.medium,
                    color = primaryContainerColor
                ) {
                    Column(
                        modifier = Modifier
                            .fillMaxWidth()
                    ) {

                        title?.invoke(this)

                        buttons
                            .filter { it.first != AlertActionStyle.Cancel }
                            .fastForEachIndexed { i, btn ->
                                if (i > 0 || hasTitle)
                                    Divider()
                                btn.second()
                            }
                    }
                }

                buttons
                    .filter { it.first == AlertActionStyle.Cancel }
                    .fastForEach {
                        Surface(
                            modifier = Modifier
                                .padding(
                                    start = ActionSheetSidePadding,
                                    end = ActionSheetSidePadding,
                                    top = ActionSheetSidePadding,
                                ),
                            shape = MaterialTheme.shapes.medium,
                            color = secondaryContainerColor
                        ) {
                            it.second()
                        }
                    }
            }
    }
}


private val ActionSheetSidePadding = 8.dp
private val ActionSheetButtonHeight : Dp = 56.dp

private val ActionSheetWindowInsets  : WindowInsets
    @Composable
    get() = WindowInsets.navigationBars.union(
        WindowInsets(
            bottom = ActionSheetSidePadding
        )
    )